#include <mpi.h>
#include "util.h"
#include "mpiexch.h"
#define DIRECTIONS 2


void StartMpi(int *id, int *np, int *argc, char ***argv) {
  int myid, nprocs;
  MPI_Init(argc,argv); /* initialize MPI environment */
  MPI_Comm_rank(MPI_COMM_WORLD, &myid); /* get task number */
  MPI_Comm_size(MPI_COMM_WORLD,&nprocs); /* get number of tasks */
  *id=myid;
  *np=nprocs;
}

void ExchMpi(struct mpiexch *p) {
            int rc;
            MPI_Status mpi_status[DIRECTIONS];
            static MPI_Request mpireq[DIRECTIONS];
            static MPI_Request mpiseq[DIRECTIONS];
            static int posted=FALSE;
	    int myid;
            MPI_Comm_rank(MPI_COMM_WORLD, &myid);
            if(!posted) {
               rc=MPI_Irecv(p->uprecv, p->nbyte, MPI_BYTE, p->up, DOWNTAG,

                           MPI_COMM_WORLD,&mpireq[0]);
               rc=MPI_Irecv(p->downrecv, p->nbyte, MPI_BYTE, p->down, UPTAG,
                           MPI_COMM_WORLD,&mpireq[1]);
               posted=TRUE;
            }
#if defined(NON_BLOCKING_SEND)
            rc=MPI_Isend(p->upsend, p->nbyte, MPI_BYTE, p->up, UPTAG, MPI_COMM_WORLD,&mpiseq[0]);
            rc=MPI_Isend(p->downsend, p->nbyte, MPI_BYTE, p->down, DOWNTAG, MPI_COMM_WORLD,&mpiseq[1]);
#else
            rc=MPI_Send(p->upsend, p->nbyte, MPI_BYTE, p->up, UPTAG, MPI_COMM_WORLD);
            rc=MPI_Send(p->downsend, p->nbyte, MPI_BYTE, p->down, DOWNTAG, MPI_COMM_WORLD);
#endif
            if(posted) {
              rc=MPI_Waitall(DIRECTIONS,mpireq,mpi_status);
            }
#if defined(NON_BLOCKING_SEND)
            rc=MPI_Waitall(DIRECTIONS,mpiseq,mpi_status);
#endif
            if(p->post) {
              rc=MPI_Irecv(p->uprecv, p->nbyte, MPI_BYTE, p->up, UPTAG,
                         MPI_COMM_WORLD,&mpireq[0]);
              rc=MPI_Irecv(p->downrecv, p->nbyte, MPI_BYTE, p->up, UPTAG,
                         MPI_COMM_WORLD,&mpireq[1]);
              posted=TRUE;
            } else {
              posted=FALSE;
            }
}

REALENE SumEnergy(REALENE e, int myid) {
  REALENE i=e, o;
  int rc;
  if(sizeof(REALENE)==sizeof(float)) {
    rc=MPI_Reduce(&i, &o, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD);
  } else {
    rc=MPI_Reduce(&i, &o, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
  }
  if(myid==0) {
    return o;
  } else {
    return 0.;
  }
}

void StopMpi() {
  int rc=MPI_Finalize();
}
